/**
 * 文件名称:  LoginServiceImpl.java
 * 文件序号:  序号
 * 内容描述:  文件简单描述，多行换行书写
 * 版权声明:  山东鸿蝶信息技术有限公司
 * 创建用户:  zhangkai
 * 创建日期:  2017/1/11 12:02
 * 修改用户:  无
 * 修改日期:  无
 * 修改说明:  无
 * 文件版本:  V1.0
 * 文件路径:
 */

package com.hongdee.rbac.login.service.impl;


import com.alibaba.fastjson.JSONObject;
import com.hongdee.base.Constant;
import com.hongdee.common.util.CrytpUtils;
import com.hongdee.common.util.TokenUtil;
import com.hongdee.rbac.login.dao.ILoginDao;
import com.hongdee.rbac.login.service.ILoginService;
import com.hongdee.rbac.user.dao.ITBcUserDao;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;

import static com.hongdee.rbac.Constant.*;

/**
 * 名  称:LoginServiceImpl
 * 类  型: class
 * 描  述: 用一句话描述类的作用
 * 路  径:com.hongdee.rbac.login.service.impl
 * 作  者:zhangkai
 * 日  期:2017/1/11 12:02
 */
@Service
public class LoginServiceImpl implements ILoginService {
    /**
     * USER_TABLE 用户表
     */
    private static final String USER_TABLE = "T_BC_USER";
    //组织表
    private static final String ORGAN_TABLE = "T_BC_ORGAN";
    //用户资源表
    private static final String USER_RESOURCE_TABLE = "T_BC_USER_RESOURCE";
    //用户角色表
    private static final String USER_ROLE_TABLE = "T_BC_ROLE";
    //资源角色表
    private static final String ROLE_RES_TABLE = "T_BC_ROLE_RESOURCE";
    //数据角色表
    private static final String DATA_TOLE = "T_BC_ROLE_DATA";
    //数据角色相关
    private static final String DATA_ROLE_REF = "T_BC_ROLE_DATA_ORG";

    private Map<String, String> userResMap;


    private Log logger = LogFactory.getLog(this.getClass());

    private enum USER_STATUS {
        DISABLE, ENABLE
    }


    @Autowired
    private ILoginDao loginDao;

    @Autowired
    private ITBcUserDao tBcUserDao;

    @Autowired
    private StringRedisTemplate stringTemplate;

    /**
     * 方法名称: child
     * 方法描述: 查询下级资源
     * 参数名称: String uid
     * 参数名称: String token
     * 返回内容: List<Map<String,Object> 资源实体转 Map 后的集合
     * 异常说明: Exception
     * 创建用户:
     * 创建时间:
     * 修改用户:
     * 修改时间:
     * 修改内容:
     */
    @Override
    public List<Map<String, Object>> child(String uid, String token) throws Exception {
        //此处做权限较验

        //现阶段直接返回
        String sqlStr = " select distinct r.id,r.res_name,r.res_ico,r.res_order  from t_bc_resource r,t_bc_role_resource rr ,t_bc_role_user " +
                " ru where r.id = rr.res_id and rr.r_id = ru.r_id and ru.u_id = ? and  r.res_type = ? and" +
                " r.res_status='1' and r.res_p_id = 0  order by r.res_order asc ";
        Object[] params = new Object[]{uid, Constant.SYSTEM};
        return this.loginDao.list(sqlStr, params);
    }

    /**
     * @param resId
     * @param uid
     * @return
     * @throws Exception
     */
    @Override
    public List leftTree(String resId, String uid) throws Exception {
        userResMap = TokenUtil.getRes(uid);
        return buildTreeChild(resId);
    }


    private List buildTreeChild(String resId) throws Exception {
        //从缓存中取得用户已有的角色

        String sqlStr = "select * from t_bc_resource where res_status='1' and res_p_id = ? order by res_order asc";
        List<Map<String, Object>> treeP = this.loginDao.list(sqlStr, resId);
        return buildTreeParent(treeP);
    }

    /**
     * 方法名称: BuildTreeParent
     * 方法描述: 获取当前节点的子节点，并生成树状结点，结合BuildTreeChild使用
     * 参数名称: List<Map<String, Object>> treeP 树节点集合
     * 返回内容: 树节点集合
     * 异常说明:
     * 创建用户:
     * 创建时间:
     * 修改用户:
     * 修改时间:
     * 修改内容:
     */
    private List buildTreeParent(List<Map<String, Object>> treeP) throws Exception {
        if (treeP.size() == 0) {
            return treeP;
        }
        List<Map<String, Object>> treeList = new ArrayList<>();
        List<Map<String, Object>> childList;
        for (Map map : treeP) {
            String resId = String.valueOf(map.get("id"));
            childList = buildTreeChild(resId);
            if (childList.size() == 0) {
                //不存在子节点时，判断当前节点是为选中节点
                if (userResMap.containsKey(resId)) {
                    treeList.add(map);
                }
                continue;
            } else {
                //存在子节点，并且子节点为按钮时，清除子节点
                Map<String, Object> temp = childList.get(0);
                String type = String.valueOf(temp.get("resType"));
                if (BTN_TYPE.equals(type)) {
                    //子节点为按钮时，去除按钮
                    map.put("child", new ArrayList());
                    treeList.add(map);
                } else {
                    //存在子节点，增加子节点 返回
                    map.put("child", childList);
                    treeList.add(map);
                }


            }

        }
        return treeList;
    }

    @Override
    public Map login(String username, String password,String clientid) throws Exception {

        /***
         * 1、根据用户 ID 查询用户数据
         * **/
        password = CrytpUtils.sha1(password);

        Map userInfo = this.loginDao.info(USER_TABLE, "u_code", username);
        if (null == userInfo || userInfo.size() == 0) {
            throw new Exception("用户不存在");
        }

        if (!password.equals(String.valueOf(userInfo.get("uPassword")))) {
            throw new Exception("用户密码错误");
        }
        //用户账号停用
        if (userInfo.get("uStatus") != null) {
            String uStatus = String.valueOf(userInfo.get("uStatus"));
            if (uStatus.equals(String.valueOf(USER_STATUS.DISABLE.ordinal()))) {
                throw new Exception("用户账号已停用，请联系管理员！");
            }
        }
        //用户验证通过，取用户 ID
        String uid = String.valueOf(userInfo.get("id"));
        //生成随机 tokenId
        String token = UUID.randomUUID().toString();
        //验证通过读取用户缓存信息
        Map<String, Object> userCache = new HashMap();
        //获取用户信息
        //获取是否是管理员

        //获取用户部门信息
        Map<String, Object> deptInfo = this.loginDao.info(ORGAN_TABLE, "id", userInfo.get("oId"));
        //获取公司信息
        Map<String, Object> company = new HashMap();
        if (null != deptInfo && COMPANY.equals(String.valueOf(deptInfo.get("oType")))) {
            company = deptInfo;
        } else {
            Map<String, Object> comTemp = this.loginDao.info(ORGAN_TABLE, "id", deptInfo.get("oPId"));
            //否则继续上行查找，直到公司信息，
            while ( comTemp.size() > 0 && !COMPANY.equals(String.valueOf(comTemp.get("oType")))) {
                comTemp = this.loginDao.info(ORGAN_TABLE, "id", comTemp.get("oPId"));
            }
            company = comTemp;
        }
        //组成公司部门信息
        Map<String, Object> orgInfo = new HashMap();
        orgInfo.put("uid", uid);
        orgInfo.put("uCode", username);
        orgInfo.put("deptId", deptInfo.get("id"));
        orgInfo.put("deptName", deptInfo.get("oName"));
        orgInfo.put("companyId", company.get("id"));
        orgInfo.put("companyName", company.get("oName"));

        //获取访问资源信息
        Map<String, String> resMap = new HashMap();
        //获取访问 URL 信息
        Map<String, String> urlMap = new HashMap();
        StringBuffer resSQL = new StringBuffer();
        resSQL.append(" SELECT ")
                .append("    ur.res_id, re.res_url")
                .append(" FROM ")
                .append("    t_bc_resource re,")
                .append("    t_bc_user_resource ur")
                .append(" WHERE ")
                .append("    re.res_status = '1'")
                .append("        AND re.id = ur.res_id")
                .append("        AND ur.u_id = ? ")
                .append(" UNION SELECT ")
                .append("    rr.res_id, re.res_url")
                .append(" FROM ")
                .append("    t_bc_role r,")
                .append("    t_bc_role_resource rr,")
                .append("    t_bc_resource re,")
                .append("    t_bc_role_user ru")
                .append(" WHERE ")
                .append("    r.r_status = '1' AND re.res_status = '1' ")
                .append("        AND r.id = rr.r_id ")
                .append("       AND ru.r_type='0' ")
                .append("        AND rr.res_id = re.id")
                .append("        AND r.id = ru.r_id")
                .append("        AND ru.u_id = ? ");
        List<Map<String, Object>> userRes = this.loginDao.list(resSQL.toString(), uid, uid);
        for (Map<String, Object> map : userRes) {
            resMap.put(String.valueOf(map.get("resId")), uid);
            urlMap.put(String.valueOf(map.get("resURL")), uid);
        }

        StringBuffer dataSql = new StringBuffer();
        dataSql.append(" SELECT ")
                .append("     rd.role_type, ro.org_id, ro.user_id ")
                .append(" FROM")
                .append("     t_bc_role_data rd,")
                .append("     t_bc_role_user ru,")
                .append("     t_bc_role_data_org ro")
                .append(" WHERE")
                .append("     rd.status = '1' AND rd.id = ru.r_id")
                .append("         AND ru.r_type = 1")
                .append("         AND ro.role_id = rd.id")
                .append("         AND ru.u_id = ?");

        //获取数据权限
        List<Map<String, Object>> dataRes = this.loginDao.list(dataSql.toString(), uid);

        Map<String, String> orgDataMap = new HashMap<>();
        Map<String, String> userDataMap = new HashMap<>();
        for (Map<String, Object> map : dataRes) {
            if (DEPT_ROLE.equals(String.valueOf(map.get("roleType")))) {
                orgDataMap.put(String.valueOf(map.get("orgId")), uid);
            } else {
                userDataMap.put(String.valueOf(map.get("userId")), uid);
            }
        }
        //根据前端路由生成

        //根据资源路由，获取其按钮
        Map<String, List<Map<String, Object>>> btnMap = new HashMap();
        String btnSQL = "select re.id , re.res_path as btnName ,re.res_url as btnUrl ,rep.res_path as page "
                + "from t_bc_resource re,t_bc_resource rep  where re.res_type='4' and re.res_status='1' "
                + " and re.res_p_id = rep.id ";
        List<Map<String, Object>> btnList = this.loginDao.list(btnSQL);

        //根据页面，生成按钮权限
        for (Map<String, Object> map : btnList) {
            String resId = String.valueOf(map.get("id"));
            List<Map<String, Object>> bl;
            //用户有此按扭权限
            if (resMap.containsKey(resId)) {
                String page = String.valueOf(map.get("page"));
                //当前页面
                if (btnMap.containsKey(page)) {
                    //已存在
                    bl = btnMap.get(page);
                    bl.add(map);
                    btnMap.put(page, bl);
                } else {
                    bl = new ArrayList<>();
                    bl.add(map);
                    btnMap.put(page, bl);
                }
            }
            continue;
        }
        //资源角色
        String resRoleSQL = "select distinct r.id,r.is_manger from t_bc_role r ,t_bc_role_user ru where r.id = ru.r_id and ru.u_id=?";
        List<Map<String, Object>> rseList = this.loginDao.list(resRoleSQL, uid);
        boolean isManger = false;
        Map resRole = new HashMap();
        for (Map<String, Object> temp : rseList) {
            resRole.put(temp.get("id"),uid);
            if ("1".equals(String.valueOf(temp.get("isManger")))) {
                isManger = true;
                continue;
            }
        }


        JSONObject cache = new JSONObject();
        cache.put("isManger", isManger);
        //用户 ID
        cache.put("uid", uid);
        //token
        cache.put("token", token);
        cache.put("user", userInfo);
        //部门信息
        cache.put("dept", deptInfo);
        //公司信息
        cache.put("company", company);
        //组织信息
        cache.put("org", orgInfo);
        //资源信息
        cache.put("res", resMap);
        //数据权限信息
        cache.put("dataOrg", orgDataMap);
        // 资源角色
        cache.put("resRole",resRole);
        //数据权限信息
        cache.put("dataUser", userDataMap);
        //按钮信息
        cache.put("btn", btnMap);
        //url 信息
        cache.put("url", urlMap);
        //手机APP登录 存信客户端ID
        cache.put("clientid",clientid);
        //载入有权限的公司、品牌、区域信息
        dataOrgCompany(cache,orgDataMap,String.valueOf(company.get("id")));
        //存入缓存
        stringTemplate.opsForValue().set(uid, cache.toString());
        userCache.put("uid", uid);
        userCache.put("token", token);
        userCache.put("org", orgInfo);
        userCache.put("user", userInfo);
        userCache.put("isAdmin",isManger);
        return userCache;
    }

    /**
     * 有权限的公司
     * @param cache
     * @param orgDataMap
     * @param companyId
     * @throws Exception
     */
    private void dataOrgCompany(JSONObject cache,Map<String,String> orgDataMap,String companyId) throws Exception {
        StringBuffer sql=new StringBuffer();
        sql.append("select  id,o_name,o_area,o_car_brand from t_bc_organ where o_p_id in(  " +
                "                 select id from t_bc_organ where o_p_id in( " +
                "                 select id from t_bc_organ where o_p_id='0' " +
                "                 ) ) and id in (");
        List<String> params=new ArrayList<>();
        for (String key : orgDataMap.keySet()) {
            sql.append( " ?, ");
            params.add(key);
        }
//        for (int i = 0; i < orgDataMap.size(); i++) {
//            sql.append("?,");
//            params.add(orgDataMap.get(i));
//        }
        sql.append("?");
        params.add(companyId);
        sql.append(")");
        List<Map<String,Object>> mapList=this.loginDao.list(sql.toString(),params.toArray());
        cache.put("dataCompany",mapList);
        //区域
        StringBuffer sqlArea=new StringBuffer();
        sqlArea.append("select dict.code,dict.label from ( ");
        sqlArea.append(sql.toString());
        sqlArea.append(") o ");
        sqlArea.append(",(select * from t_bc_newdict  where `p_code`='area') dict where o.o_area=dict.`code` group by o.o_area");
        List<Map<String,Object>> areaMapList=this.loginDao.list(sqlArea.toString(),params.toArray());
        cache.put("dataArea",areaMapList);
        //品牌

        StringBuffer sqlBrand=new StringBuffer();
        sqlBrand.append("select dict.b_code `code`,dict.b_name label from ( ");
        sqlBrand.append(sql.toString());
        sqlBrand.append(") o ");
        sqlBrand.append(",T_BC_BRAND dict where  o.o_car_brand = dict.b_code group by o.o_car_brand ");
        List<Map<String,Object>> carBusMapList=this.loginDao.list(sqlBrand.toString(),params.toArray());

        cache.put("dataBrand",carBusMapList);
    }

}
